package com.infolab.aims.service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.infolab.aims.GlobalConstant;
import com.infolab.aims.domain.Location;
import com.infolab.aims.domain.SystemCodeType;
import com.infolab.aims.domain.Vendor;
import com.infolab.aims.domain.VendorAsset;
import com.infolab.aims.domain.asset.AssetModel;
import com.infolab.aims.domain.asset.AssetTransaction;
import com.infolab.aims.domain.asset.AssetTransactionItem;
import com.infolab.aims.domain.purchase.PurchaseOrder;
import com.infolab.aims.domain.purchase.PurchaseOrderDetail;
import com.infolab.aims.domain.purchase.PurchaseOrderRepair;
import com.infolab.aims.domain.receive.DeliveryOrder;
import com.infolab.aims.domain.receive.DeliveryOrderComponent;
import com.infolab.aims.domain.receive.DeliveryOrderEquipment;
import com.infolab.aims.service.intf.AssetModelService;
import com.infolab.aims.service.intf.AssetTransactionFacadeService;
import com.infolab.aims.service.intf.AssetTransactionService;
import com.infolab.aims.service.intf.DeliveryOrderService;
import com.infolab.aims.service.intf.PurchaseOrderService;
import com.infolab.aims.service.intf.VendorService;


@Service
@Transactional
public class AssetTransactionFacadeServiceImpl implements AssetTransactionFacadeService {
	
	Log logger = LogFactory.getLog(getClass());
	@PersistenceContext
	private EntityManager em;
	
	@Autowired
	private AssetModelService assetModelService;
	
	@Autowired
	private PurchaseOrderService purchaseOrderService;
	
	@Autowired
	private DeliveryOrderService deliveryOrderService;
	
	@Autowired
	private AssetTransactionService assetTransactionService;
	
	@Autowired
	private VendorService vendorService;
	
	
	public void createDeliveryOrder(DeliveryOrder deliveryOrder)
	{
		
		deliveryOrderService.createDeliveryOrder(deliveryOrder);
		
		logger.info("Create Delivery Order "+ deliveryOrder.getDeliveryOrderCode());
		
		PurchaseOrder purchaseOrder = deliveryOrder.getPurchaseOrder();
		
		if(purchaseOrder.isNewPurchaseOrder())
		{
			boolean completePurchaseOrder = true;
			AssetTransaction assetTransaction = new AssetTransaction();
			
			List<AssetTransactionItem> assetTransactionItems = new ArrayList<AssetTransactionItem>();
			Location location = deliveryOrder.getLocation();
			
			assetTransaction.setAccessDepartment(deliveryOrder.getAccessDepartment());
			assetTransaction.setToLocation(location);
			assetTransaction.setCreatedBy(deliveryOrder.getCreatedBy());
			assetTransaction.setApprovedBy(deliveryOrder.getCreatedBy());
			assetTransaction.setModifiedBy(deliveryOrder.getCreatedBy());
			assetTransaction.setDateCreated(deliveryOrder.getDeliveryOrderDate());
			assetTransaction.setDateModified(new Date());
			assetTransaction.setApprovedDate(new Date());
			assetTransaction.setCompanyCode(purchaseOrder.getCompanyCode());
			assetTransaction.setRemarks(deliveryOrder.getDeliveryOrderCode());
			
			if(deliveryOrder.isComponentDeliveryOrder())
			{
				assetTransaction.setAssetType(AssetModel.ASSETTYPE_COMPONENT);
				List<DeliveryOrderComponent> deliveryOrderComponents = deliveryOrder.getDeliveryOrderComponents();
				if(deliveryOrderComponents!=null)
				{
					for(int i=0;i<deliveryOrderComponents.size();i++)
					{
						DeliveryOrderComponent deliveryOrderComponent = deliveryOrderComponents.get(i);
						AssetTransactionItem assetTransactionItem = new AssetTransactionItem();						
						assetTransactionItem.setAssetTransactionQuantity(deliveryOrderComponent.getQuantityReceiving());
						assetTransactionItem.setAssetPrice(deliveryOrderComponent.getUnitPrice());
						assetTransactionItem.setAssetModel(deliveryOrderComponent.getAssetModel());
						assetTransactionItem.setAssetTag(deliveryOrderComponent.getAssetTag());
						assetTransactionItem.setLocation(location);
						assetTransactionItem.setCompanyCode(purchaseOrder.getCompanyCode());
						assetTransactionItems.add(assetTransactionItem);
						
						
						PurchaseOrderDetail purchaseOrderDetail = purchaseOrder.findPurchaseOrderDetails(deliveryOrderComponent.getAssetModel());
						Integer qtyReceived = purchaseOrderDetail.getQuantityReceived();
						if(qtyReceived==null)
							qtyReceived = 0;
						
						qtyReceived = qtyReceived + deliveryOrderComponent.getQuantityReceiving();
						purchaseOrderDetail.setQuantityReceived(qtyReceived);
						
						if(qtyReceived.intValue()<purchaseOrderDetail.getQuantityOrder().intValue())
							completePurchaseOrder = false;
					}
				}
			}
			else if(deliveryOrder.isEquipmentDeliveryOrder())
			{
				assetTransaction.setAssetType(AssetModel.ASSETTYPE_EQUIPMENT);
				assetTransaction.setCreatedBy(deliveryOrder.getCreatedBy());
				assetTransaction.setApprovedBy(deliveryOrder.getCreatedBy());
				assetTransaction.setModifiedBy(deliveryOrder.getCreatedBy());
				assetTransaction.setDateModified(new Date());
				assetTransaction.setApprovedDate(new Date());
				assetTransaction.setCompanyCode(purchaseOrder.getCompanyCode());
				List<DeliveryOrderEquipment> deliveryOrderEquipments = deliveryOrder.getDeliveryOrderEquipments();
				
				List<PurchaseOrderDetail> purchaseOrderDetails = purchaseOrder.getPurchaseOrderDetails();
				
				if(deliveryOrderEquipments!=null)
				{
					for(int i=0;i<deliveryOrderEquipments.size();i++)
					{
						DeliveryOrderEquipment deliveryOrderEquipment = deliveryOrderEquipments.get(i);
						
						AssetTransactionItem assetTransactionItem = new AssetTransactionItem();
						assetTransactionItem.setSerialNo(deliveryOrderEquipment.getReceivedSerialNo());
						assetTransactionItem.setAssetPrice(deliveryOrderEquipment.getUnitPrice());
						assetTransactionItem.setAssetTag(deliveryOrderEquipment.getAssetTag());
						assetTransactionItem.setLocation(location);
						assetTransactionItem.setAssetModel(deliveryOrderEquipment.getAssetModel());
						assetTransactionItem.setCompanyCode(purchaseOrder.getCompanyCode());
						
						PurchaseOrderDetail purchaseOrderDetail = purchaseOrder.findPurchaseOrderDetails(deliveryOrderEquipment.getAssetModel());
						if(purchaseOrderDetail!=null)
						{
							Integer qtyReceived = purchaseOrderDetail.getQuantityReceived();
							if(qtyReceived==null)
								qtyReceived = 0;
							
							qtyReceived = qtyReceived + 1;
							purchaseOrderDetail.setQuantityReceived(qtyReceived);
							
							assetTransactionItems.add(assetTransactionItem);
						}
					}
					
					for(int i=0;i<purchaseOrderDetails.size();i++)
					{
						PurchaseOrderDetail purchaseOrderDetail = purchaseOrderDetails.get(i);
						if(purchaseOrderDetail.getQuantityReceived().intValue()<purchaseOrderDetail.getQuantityOrder().intValue())
						{
							completePurchaseOrder = false;
							break;
						}
					}
					
				}
			}
			
			logger.info("Purchase Order completed  "+completePurchaseOrder);
			
			if(completePurchaseOrder)
				purchaseOrder.setPurchaseOrderStatus(PurchaseOrder.PURCHASEORDERSTATUS_CLOSED);
			else
				purchaseOrder.setPurchaseOrderStatus(PurchaseOrder.PURCHASEORDERSTATUS_INPROCESS);
			
			purchaseOrderService.updatePurchaseOrder(purchaseOrder);
			
			assetTransaction.setAssetTransactionItems(assetTransactionItems);
			
			assetTransaction.setVendor(purchaseOrder.getVendor());
			
			assetTransactionService.createReceiveNewDeliveryOrder(assetTransaction,deliveryOrder.getEffectiveStartDate(),deliveryOrder.getEffectiveEndDate());
		}
		else if(purchaseOrder.isRepairPurchaseOrder())
		{
			boolean completePurchaseOrder = true;
						
			List<DeliveryOrderEquipment> deliveryOrderEquipments = deliveryOrder.getDeliveryOrderEquipments();
			
			AssetTransaction assetTransaction = new AssetTransaction();
			List<AssetTransactionItem> assetTransactionItems = new ArrayList<AssetTransactionItem>();
			
			assetTransaction.setAccessDepartment(deliveryOrder.getAccessDepartment());
			
			//TODO: must look vendor id from lookup table
			Location vendorLocation = getVendorRepairLocation();
			assetTransaction.setFromLocation(vendorLocation);
			assetTransaction.setToLocation(deliveryOrder.getLocation());
			assetTransaction.setDateCreated(deliveryOrder.getDeliveryOrderDate());
			assetTransaction.setCreatedBy(deliveryOrder.getCreatedBy());
			assetTransaction.setApprovedBy(deliveryOrder.getCreatedBy());
			assetTransaction.setModifiedBy(deliveryOrder.getCreatedBy());
			assetTransaction.setDateModified(new Date());
			assetTransaction.setApprovedDate(new Date());
			assetTransaction.setCompanyCode(purchaseOrder.getCompanyCode());
			assetTransaction.setRemarks(deliveryOrder.getDeliveryOrderCode());
			
			if(deliveryOrderEquipments!=null)
			{
				for(int i=0;i<deliveryOrderEquipments.size();i++)
				{
					DeliveryOrderEquipment deliveryOrderEquipment = deliveryOrderEquipments.get(i);
					if(deliveryOrderEquipment.isActive())
					{
						PurchaseOrderRepair purchaseOrderRepair= purchaseOrder.findPurchaseOrderRepairs(deliveryOrderEquipment.getAssetModel(),deliveryOrderEquipment.getReceivedSerialNo());
						if(purchaseOrderRepair!=null)
						{
							purchaseOrderRepair.setRepairStatus(PurchaseOrderRepair.REPAIRSTATUS_RECEIVED);
							
							String serialNo = purchaseOrderRepair.getSerialNo();
							AssetModel assetModel = purchaseOrderRepair.getAssetModel();
							
							AssetTransactionItem assetTransactionItem = new AssetTransactionItem();
							assetTransactionItem.setSerialNo(serialNo);
							assetTransactionItem.setAssetPrice(0f);
							assetTransactionItem.setAssetModel(assetModel);
							assetTransactionItem.setCompanyCode(purchaseOrder.getCompanyCode());
							if(deliveryOrderEquipment.getStatus().equalsIgnoreCase(AssetModel.ASSETSTATUS_ACTIVE))
							{
								assetTransactionItem.setRemarks(AssetModel.ASSETSTATUS_ACTIVE);
							}
							
							else
							{
								assetTransactionItem.setRemarks(AssetModel.ASSETSTATUS_FAULT);
							}
							assetTransactionItems.add(assetTransactionItem);
						}
					}
				}
				
			}
			
			List<PurchaseOrderRepair> purchaseOrderRepairs = purchaseOrder.getPurchaseOrderRepairs();
			if(purchaseOrderRepairs!=null)
			{
				for(int i=0;i<purchaseOrderRepairs.size();i++)
				{
					PurchaseOrderRepair purchaseOrderRepair = purchaseOrderRepairs.get(i);
					if(!purchaseOrderRepair.isReceived())
						completePurchaseOrder=false;
				}
			}
			
			logger.info("Purchase Order completed "+completePurchaseOrder);
			
			if(completePurchaseOrder)
				purchaseOrder.setPurchaseOrderStatus(PurchaseOrder.PURCHASEORDERSTATUS_CLOSED);
			else
				purchaseOrder.setPurchaseOrderStatus(PurchaseOrder.PURCHASEORDERSTATUS_INPROCESS);
			
			purchaseOrderService.updatePurchaseOrder(purchaseOrder);
			
			assetTransaction.setAssetTransactionItems(assetTransactionItems);
			
			assetTransactionService.createReceiveRepairDeliveryOrder(assetTransaction);
			
		}
	}

	public void createPurchaseOrder(PurchaseOrder purchaseOrder) {
		
		purchaseOrderService.createPurchaseOrder(purchaseOrder);
		logger.info("Create Purchase Order "+  purchaseOrder.getPurchaseOrderCode());
		
		if(purchaseOrder.isNewPurchaseOrder()) 			// updating vendor price
		{
			Vendor vendor = vendorService.getVendor(purchaseOrder.getVendor().getVendorId());
			List<PurchaseOrderDetail> purchaseOrderDetails = purchaseOrder.getPurchaseOrderDetails();
			if(purchaseOrderDetails!=null)
			{
				for(int i=0;i<purchaseOrderDetails.size();i++)
				{
					PurchaseOrderDetail purchaseOrderDetail = purchaseOrderDetails.get(i);
					AssetModel assetModel = purchaseOrderDetail.getAssetModel();
					VendorAsset vendorAsset = vendor.findVendorAsset(assetModel);
					if(vendorAsset!=null)
					{
						vendorAsset.setUnitPrice(purchaseOrderDetail.getUnitPrice());
						vendorAsset.setPurchaseOrderCode(purchaseOrder.getPurchaseOrderCode());
						vendorAsset.setPurchaseOrderDate(purchaseOrder.getPurchaseOrderDate());
						em.merge(vendorAsset);
					}
					else
					{
						vendorAsset = new VendorAsset();
						vendorAsset.setAssetModel(assetModel);
						vendorAsset.setVendor(vendor);
						vendorAsset.setUnitPrice(purchaseOrderDetail.getUnitPrice());
						vendorAsset.setPurchaseOrderCode(purchaseOrder.getPurchaseOrderCode());
						vendorAsset.setPurchaseOrderDate(purchaseOrder.getPurchaseOrderDate());
						em.persist(vendorAsset);
					}
				}
			}
		}
		else if(purchaseOrder.isRepairPurchaseOrder()) // update equipment status to repair
		{
			AssetTransaction assetTransaction = new AssetTransaction();
			
			List<AssetTransactionItem> assetTransactionItems = new ArrayList<AssetTransactionItem>();
			Location fromLocation = purchaseOrder.getLocation();
			
			assetTransaction.setAccessDepartment(purchaseOrder.getAccessDepartment());
			assetTransaction.setFromLocation(fromLocation);
			
			Location vendorLocation = getVendorRepairLocation();
			assetTransaction.setToLocation(vendorLocation);
			assetTransaction.setDateCreated(purchaseOrder.getPurchaseOrderDate());
			assetTransaction.setCreatedBy(purchaseOrder.getCreatedBy());
			assetTransaction.setApprovedBy(purchaseOrder.getCreatedBy());
			assetTransaction.setModifiedBy(purchaseOrder.getCreatedBy());
			assetTransaction.setDateModified(new Date());
			assetTransaction.setApprovedDate(new Date());
			assetTransaction.setCompanyCode(purchaseOrder.getCompanyCode());
			assetTransaction.setRemarks(purchaseOrder.getPurchaseOrderCode());
			
			List<PurchaseOrderRepair> purchaseOrderRepairs = purchaseOrder.getPurchaseOrderRepairs();
			if(purchaseOrderRepairs!=null) {
				for (int i = 0; i < purchaseOrderRepairs.size(); i++) {
					PurchaseOrderRepair purchaseOrderRepair = purchaseOrderRepairs.get(i);
					if(!purchaseOrderRepair.isDeleted()){
					AssetModel assetModel = purchaseOrderRepair.getAssetModel();
					String serialNo = purchaseOrderRepair.getSerialNo();

					AssetTransactionItem assetTransactionItem = new AssetTransactionItem();
					assetTransactionItem.setSerialNo(serialNo);
					assetTransactionItem.setAssetPrice(0f);
					assetTransactionItem.setAssetModel(assetModel);
					assetTransactionItem.setCompanyCode(purchaseOrder.getCompanyCode());
					assetTransactionItems.add(assetTransactionItem);
					}
				}
			}
			
			assetTransaction.setAssetTransactionItems(assetTransactionItems);
			
			assetTransactionService.createRepairPurchaseOrder(assetTransaction);
		}
	}
	
	private Location getVendorRepairLocation()
	{
		try
		{
			Query query = em.createQuery("from SystemCodeType where systemCodeTypeCode='"+GlobalConstant.SYSTEM_CODE_TYPE_VENDOR_REPAIR_LOCATION+"'");
			SystemCodeType systemCodeType = (SystemCodeType) query.getSingleResult();
			query = em.createQuery("from Location where locationCode='"+systemCodeType.getSystemCodeTypeValue()+"'");
			Location location = (Location) query.getSingleResult();
			return location;
		}catch(NoResultException ex)
		{
			logger.error("Can't get location for vendor repair location");
		}

		return null;
	}

	
}
